/**
 * Copyright 2008 floop.pl
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 *  
 * http://www.apache.org/licenses/LICENSE-2.0 
 *  
 * Unless required by applicable law or agreed to in writing, software distributed
 * under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
package org.eaicompiler.model;

import java.util.HashMap;
import java.util.Map;

import org.eaicompiler.antlr.exceptions.UndefinedConstantException;

/**
 * Generic class for defines
 * @author floop.pl
 */
public class Defines {
	public final static int DEFINE_UNKNOWN = -1;
	public final static int DEFINE_FLAG  = 0;
	public final static int DEFINE_UNIT_FIELD = 1;
	public final static int DEFINE_SPELL = 2;
	public final static int DEFINE_EMOTE = 3;
	public final static int DEFINE_QUEST = 4;
	public final static int DEFINE_SOUND = 5;
	public final static int DEFINE_CREATURE = 6;
	public final static int DEFINE_INSTANCE_FIELD = 7;
	public final static int DEFINE_TEMPLATE = 8;
	public final static int DEFINE_TYPES_COUNT = 9;
	
	private Map <Integer, Map<String, Integer>> definesMaps;
	private Map <Integer, Map<Integer, String>> inverseDefinesMaps;
	private Map <Integer, Map<Integer, Boolean>> inverseDefinesUsedMaps;

	public Map<Integer, Boolean> getInverseDefinesUsed(int definesType)
	{
		Map<Integer, Boolean> result = null;
		if(inverseDefinesUsedMaps==null)
		{
			inverseDefinesUsedMaps = new HashMap<Integer, Map<Integer, Boolean>>();
		}
		result = inverseDefinesUsedMaps.get(new Integer(definesType));
		if(result==null)
		{
			inverseDefinesUsedMaps.put(new Integer(definesType), new HashMap<Integer, Boolean>());
			result = inverseDefinesUsedMaps.get(new Integer(definesType));
		}
		return result;				
	}
	
	public Map<Integer, String> getInverseDefines(int definesType)
	{
		Map<Integer, String> result = null;
		if(inverseDefinesMaps==null)
		{
			inverseDefinesMaps = new HashMap<Integer, Map<Integer, String>>();
		}
		result = inverseDefinesMaps.get(new Integer(definesType));
		if(result==null)
		{
			inverseDefinesMaps.put(new Integer(definesType), new HashMap<Integer, String>());
			result = inverseDefinesMaps.get(new Integer(definesType));
		}
		return result;		
	}
	
	public Map<String, Integer> getDefines(int definesType)
	{
		Map<String, Integer> result = null;
		if(definesMaps==null)
		{
			definesMaps = new HashMap<Integer, Map<String, Integer>>();
		}
		result = definesMaps.get(new Integer(definesType));
		if(result==null)
		{
			definesMaps.put(new Integer(definesType), new HashMap<String, Integer>());
			result = definesMaps.get(new Integer(definesType));
		}
		return result;
	}
	
	public void define(int definesType, String define, int value)
	{
		Map<String, Integer> map = getDefines(definesType);
		map.put(define, new Integer(value));
		Map<Integer, String> imap = getInverseDefines(definesType);
		imap.put(new Integer(value), define);
	}
	
	public int resolve(int definesType, String define)
	{
		int result = 0;
		Map<String, Integer> map = getDefines(definesType);
		Integer i = map.get(define);
		if (i != null) {
			result = i.intValue();
		} else {
			try {
				result = Integer.parseInt(define);				
			} catch (NumberFormatException e) {
				throw new UndefinedConstantException(define + " is not defined");
			}
		}
		return result;		
	}

	public String inverseResolve(int definesType, int value) {
		Map<Integer, String> map = getInverseDefines(definesType);
		String v = map.get(new Integer(value));
		if(v!=null)
		{
			getInverseDefinesUsed(definesType).put(new Integer(value), new Boolean(true));
		}
		return v;
	}
}
